package mandel;

public class Coordinates {

	protected static int DELTA_X_AT_ZOOM_1 = 4;
	
	protected double xMin, xMax, yMin, yMax;
	protected int nbPixelLarg_disp, nbPixelHaut_disp;
	protected int nbPixelLarg_aa, nbPixelHaut_aa;

	protected double zoomLevel;
	protected double xCenterView, yCenterView;
	
	protected static int tailleAA;
	
	public Coordinates(int tailleAA) {
		
		// visu dissymétrique (pour test perf multithread)
//		xCenterView = -0.5430892904133817;
//		yCenterView = 0.5711363551811154;
//		zoomLevel = 25251;
		
		this.tailleAA = tailleAA;
		
		nbPixelLarg_disp = 100;
		nbPixelHaut_disp = 100;
		nbPixelLarg_aa = 100 * tailleAA;
		nbPixelHaut_aa = 100 * tailleAA;

		//visu par defaut
		setDefaultView();
	}

	public void changeTailleAA(int newTailleAA) {
		this.tailleAA = newTailleAA;
		nbPixelLarg_aa = nbPixelLarg_disp * tailleAA;
		nbPixelHaut_aa = nbPixelHaut_disp * tailleAA;
	}
	
	//**************************************************************************
	// Modifs des coordonnées
	
	public final void setDefaultView() {
		xCenterView = -0.5;
		yCenterView = 0;
		zoomLevel = 1;
		computeBounds_from_centerView_Zoom();
	}
	public void setView1() {
		xCenterView = -0.5606537413825414;
		yCenterView = 0.5575960201928644;
		zoomLevel = 6.7108864E7;
		computeBounds_from_centerView_Zoom();
	}
	
		

	
	public void panelSizeChanged(int newW, int newH) {
		nbPixelLarg_disp = newW;
		nbPixelHaut_disp = newH;
		nbPixelLarg_aa = newW * tailleAA;
		nbPixelHaut_aa = newH * tailleAA;

		computeBounds_from_centerView_Zoom();
	}
	
	public void setView(double xCenterView_new, double yCenterView_new, double zoomLevel_new) {
		xCenterView = xCenterView_new;
		yCenterView = yCenterView_new;
		zoomLevel = zoomLevel_new;
		computeBounds_from_centerView_Zoom();
	}
	
	public void zoomWithPointInvariant(double xInvariant, double yInvariant, double zoomLevel_new) {
		double k = (1/zoomLevel - 1/zoomLevel_new) / (1/zoomLevel);
		xCenterView = xCenterView + k*(xInvariant-xCenterView);
		yCenterView = yCenterView + k*(yInvariant-yCenterView);
		zoomLevel = zoomLevel_new;
		computeBounds_from_centerView_Zoom();
	}
	
	// A partir d'un centre de vue et d'un niveau de zoom, renvoie les coordonnées extremes
	private void computeBounds_from_centerView_Zoom() {
		double deltaX = 4.0/zoomLevel;
		double deltaY = deltaX * nbPixelHaut_disp / nbPixelLarg_disp;
		xMin = xCenterView - deltaX/2;
		xMax = xCenterView + deltaX/2;
		yMin = yCenterView - deltaY/2;
		yMax = yCenterView + deltaY/2;
	}
	
	
	//**************************************************************************
	// fonctions utiles
	
	public Coordinates getCopy() {
		return getCopy(this.tailleAA);
	}
	public Coordinates getCopy(int newTailleAA) {
		Coordinates coords_new = new Coordinates(newTailleAA);
		coords_new.nbPixelLarg_disp = this.nbPixelLarg_disp;
		coords_new.nbPixelHaut_disp = this.nbPixelHaut_disp;
		coords_new.nbPixelLarg_aa = this.nbPixelLarg_disp * newTailleAA;
		coords_new.nbPixelHaut_aa = this.nbPixelHaut_disp * newTailleAA;
		coords_new.setView(this.xCenterView, this.yCenterView, this.zoomLevel);
		return coords_new;
	}
	
	public double get_xMin() {return xMin;}
	public double get_xMax() {return xMax;}
	public double get_yMin() {return yMin;}
	public double get_yMax() {return yMax;}
	public double get_zoomLevel() {return zoomLevel;}
	public double get_xCenterView() {return xCenterView;}
	public double get_yCenterView() {return yCenterView;}
	public int get_nbPixelLarg_disp() {return nbPixelLarg_disp;}
	public int get_nbPixelHaut_disp() {return nbPixelHaut_disp;}
	public int get_nbPixelLarg_aa() {return nbPixelLarg_aa;}
	public int get_nbPixelHaut_aa() {return nbPixelHaut_aa;}
	public int getTailleAA() {return tailleAA;}
	
	public int getNbPixels_disp() {
		return nbPixelLarg_disp * nbPixelHaut_disp;
	}
	public int getNbPixels_aa() {
		return nbPixelLarg_aa * nbPixelHaut_aa;
	}
	
	public double getXFromI_disp(double i) {
		return xMin + i * (xMax-xMin)/nbPixelLarg_disp;
	}
	public double getXFromI_aa(double i) {
		return xMin + i * (xMax-xMin)/nbPixelLarg_aa;
	}
	public double getYFromJ_disp(double j) {
		return yMin + (nbPixelHaut_disp-j) * (yMax-yMin)/nbPixelHaut_disp;
	}
	public double getYFromJ_aa(double j) {
		return yMin + (nbPixelHaut_aa-j) * (yMax-yMin)/nbPixelHaut_aa;
	}
	
	public int getIFromX_disp(double x) {
		return UtilsCalcul.round2int((x-xMin) * nbPixelLarg_disp / (xMax-xMin));
	}
	public int getIFromX_aa(double x) {
		return UtilsCalcul.round2int((x-xMin) * nbPixelLarg_aa / (xMax-xMin));
	}
	public int getJFromY_disp(double y) {
		return UtilsCalcul.round2int(nbPixelHaut_disp - (y - yMin) * nbPixelHaut_disp / (yMax-yMin));
	}
	public int getJFromY_aa(double y) {
		return UtilsCalcul.round2int(nbPixelHaut_aa - (y - yMin) * nbPixelHaut_aa / (yMax-yMin));
	}
	
	// sert pour les strech entre 2 images
	public double getIFromX_precis_aa(double x) {
		return (x-xMin) * nbPixelLarg_aa / (xMax-xMin);
	}
	public double getJFromY_precis_aa(double y) {
		return nbPixelHaut_aa - (y - yMin) * nbPixelHaut_aa / (yMax-yMin);
	}

	
}
